package com.sq.util;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sq.util.exception.CommonException;

public class JsonUtil {
    private static Logger log = LoggerFactory.getLogger(JsonUtil.class);

    private static ObjectMapper mapper = new ObjectMapper(); // can reuse, share

    static {
        // 忽略不存在的参数
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public static String toJson(Object obj) {
        if (obj == null) {
            return null;
        }
        try {
            return mapper.writeValueAsString(obj);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CommonException(e.getMessage());
        }
    }

    public static String toJson(Object obj, Class<?> cls) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        List<Field> l = BeanUtil.getFields(cls);
        try {
            for (Field field : l) {
                String name = field.getName();
                Object o = BeanUtil.getProperty(obj, name);
                map.put(name, o);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CommonException(e.getMessage());
        }
        return toJson(map);
    }

    public static <T> T toObject(String content, Class<T> valueType) {
        if (StringUtil.isBlank(content)) {
            return null;
        }
        try {
            return mapper.readValue(content, valueType);
        } catch (Exception e) {
            log.error("content<" + content + ">转换出错", e);
            throw new CommonException(e.getMessage());
        }
    }

    /**
     * json转List
     * 
     * @param content
     *            json数据
     * @param valueType
     *            泛型数据类型
     * @return
     */
    public static <T> List<T> toListObject(String content, Class<T> valueType) {
        try {
            return mapper.readValue(content, mapper.getTypeFactory().constructParametricType(List.class, valueType));
        } catch (Exception e) {
            log.error("content<" + content + ">转换出错", e);
            throw new CommonException(e.getMessage());
        }
    }

    public static Map<?, ?> toMap(String content) {
        if (StringUtil.isBlank(content)) {
            return null;
        }
        try {
            Map<?, ?> map = mapper.readValue(content, Map.class);
            return map;
        } catch (Exception e) {
            log.error("content<" + content + ">转换出错", e);
            throw new CommonException(e.getMessage());
        }
    }

    private static final String SPLIT = ".class,";
    private static final String LIST = "###list";
    private static final String MAP = "###MAP";

    /**
     * 序列化一个对象
     */
    public static String serialize(Object object) {
        if (object == null) {
            return "";
        }
        try {
            if (isListClass(object.getClass())) {
                return serializeWithList(object);
            }
            if (isMapClass(object.getClass())) {
                return serializeWithMap(object);
            }
            // 普通对象
            return serializeWithCommon(object);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CommonException(e.getMessage());
        }
    }

    /**
     * 发序列化成一个对象
     */
    public static Object unserialize(String content) {
        if (StringUtil.isBlank(content)) {
            return null;
        }
        try {
            int index = content.indexOf(SPLIT);
            String className = content.substring(0, index);
            if (LIST.equals(className)) {
                String json = content.substring(index + SPLIT.length());
                return unserializeWithList(json);
            }
            if (MAP.equals(className)) {
                String json = content.substring(index + SPLIT.length());
                return unserializeWithMap(json);
            }
            // 普通对象
            String json = content.substring(index + SPLIT.length());
            Class<?> cls = getClass(className);
            return JsonUtil.toObject(json, cls);
        } catch (Exception e) {
            log.error("content<" + content + ">转换出错", e);
            throw new CommonException(e.getMessage());
        }
    }

    /**
     * 序列化一个map对象
     */
    public static String serializeMap(Map<String, Object> map) {
        if (MapUtil.isEmpty(map)) {
            return "";
        }
        try {
            Map<String, String> newMap = new HashMap<String, String>();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                newMap.put(entry.getKey(), serialize(entry.getValue()));
            }
            return toJson(newMap);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new CommonException(e.getMessage());
        }
    }

    /**
     * 反序列化一个map对象
     */
    public static Map<String, Object> unserializeMap(String content) {
        if (StringUtil.isBlank(content)) {
            return new HashMap<String, Object>(1);
        }
        try {
            Map<?, ?> newMap = toMap(content);
            Map<String, Object> resultMap = new HashMap<String, Object>();
            for (Map.Entry<?, ?> entry : newMap.entrySet()) {
                resultMap.put(entry.getKey().toString(), unserialize(entry.getValue().toString()));
            }
            return resultMap;
        } catch (Exception e) {
            log.error("content<" + content + ">转换出错", e);
            throw new CommonException(e.getMessage());
        }
    }

    public static JavaType constructParametricType(Class<?> parametrized, Class<?>... parameterClasses) {
        return mapper.getTypeFactory().constructParametricType(parametrized, parameterClasses);
    }

    public static JavaType constructParametricType(Class<?> rawType, JavaType... parameterTypes) {
        return mapper.getTypeFactory().constructParametricType(rawType, parameterTypes);
    }

    public static JavaType constructType(Type type) {
        return mapper.getTypeFactory().constructType(type);
    }

    public static <T> T readValue(String content, JavaType valueType) throws Exception {
        return mapper.readValue(content, valueType);
    }

    private static Map<String, Class<?>> clsCache = new HashMap<String, Class<?>>();

    private static Class<?> getClass(String className) {
        Class<?> cls = clsCache.get(className);
        if (cls != null) {
            return cls;
        }
        try {
            cls = Class.forName(className);
            clsCache.put(className, cls);
            return cls;
        } catch (ClassNotFoundException e) {
            log.error("找不到类<" + className + ">");
            throw new CommonException(e.getMessage());
        }
    }

    static boolean isListClass(Class<?> cls) {
        Class<?>[] arr = cls.getInterfaces();
        for (Class<?> c : arr) {
            if (List.class.equals(c)) {
                return true;
            }
        }
        return false;
    }

    static boolean isMapClass(Class<?> cls) {
        Class<?>[] arr = cls.getInterfaces();
        for (Class<?> c : arr) {
            if (Map.class.equals(c)) {
                return true;
            }
        }
        return false;
    }

    private static String serializeWithCommon(Object object) {
        String className = object.getClass().getName();
        String json = JsonUtil.toJson(object);
        return className + SPLIT + json;
    }

    private static String serializeWithMap(Object object) {
        Map<?, ?> map = (Map<?, ?>) object;
        // 空MAP的处理
        if (MapUtil.isEmpty(map)) {
            return MAP + SPLIT;
        }
        Map<String, String> newMap = new HashMap<String, String>();
        for (Map.Entry<?, ?> entry : map.entrySet()) {
            newMap.put(serialize(entry.getKey()), serialize(entry.getValue()));
        }
        String json = toJson(newMap);
        return MAP + SPLIT + json;
    }

    private static String serializeWithList(Object object) {
        List<?> list = (List<?>) object;
        // 空数组的处理
        if (ListUtil.isEmpty(list)) {
            return LIST + SPLIT;
        }
        // 非空数组先验证一下里面的对象是否一致,这里只是简单校验一下前后对象是否一致
        Object first = list.get(0);
        Object last = list.get(list.size() - 1);
        CommonException.isTrue(first.getClass().equals(last.getClass()), "List里面的对象不一致，不支持该对象序列化");

        String className = first.getClass().getName();
        String json = JsonUtil.toJson(object);
        return LIST + SPLIT + className + SPLIT + json;
    }

    private static Object unserializeWithMap(String json) {
        if (StringUtil.isBlank(json)) {
            return Collections.emptyMap();
        }
        Map<?, ?> newMap = toMap(json);
        Map<Object, Object> resultMap = new HashMap<Object, Object>();
        for (Map.Entry<?, ?> entry : newMap.entrySet()) {
            resultMap.put(unserialize(entry.getKey().toString()), unserialize(entry.getValue().toString()));
        }
        return resultMap;
    }

    private static Object unserializeWithList(String json) {
        if (StringUtil.isBlank(json)) {
            return Collections.emptyList();
        }
        int index = json.indexOf(SPLIT);
        String className = json.substring(0, index);
        json = json.substring(index + SPLIT.length());
        Class<?> cls = getClass(className);
        return JsonUtil.toListObject(json, cls);
    }
}
